package ar.uade.distribuidas.tpo.dba.servicio;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.joda.time.DateTime;
import org.joda.time.LocalDate;

import ar.uade.distribuidas.tpo.base.dominiodto.ClienteDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.CondicionDeVentaDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.CotizacionDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.EstadoItemPedido;
import ar.uade.distribuidas.tpo.base.dominiodto.EstadoOC;
import ar.uade.distribuidas.tpo.base.dominiodto.EstadoRemito;
import ar.uade.distribuidas.tpo.base.dominiodto.FacturaDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ItemCotizacionDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ItemListaPrecioDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ItemListaRodamientoDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ItemPedidoDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ItemRemitoDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ItemSolicitudDeCotizacionDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ListaPrecioDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.OrdenDeCompraDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.OrdenDePedidoDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.PoliticaDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.ProveedorDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.RemitoCPEDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.RemitoDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.RodamientoDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.SolicitudDeCotizacionDTO;
import ar.uade.distribuidas.tpo.base.dominiodto.StockDTO;
import ar.uade.distribuidas.tpo.base.remoto.IGestion;
import ar.uade.distribuidas.tpo.base.utils.FormatUtils;
import ar.uade.distribuidas.tpo.dba.dao.ClienteDAO;
import ar.uade.distribuidas.tpo.dba.dao.CondicionDeVentaDAO;
import ar.uade.distribuidas.tpo.dba.dao.CotizacionDAO;
import ar.uade.distribuidas.tpo.dba.dao.FacturaDAO;
import ar.uade.distribuidas.tpo.dba.dao.ItemListaPrecioDAO;
import ar.uade.distribuidas.tpo.dba.dao.ListaPrecioDAO;
import ar.uade.distribuidas.tpo.dba.dao.OrdenDeCompraDAO;
import ar.uade.distribuidas.tpo.dba.dao.OrdenDePedidoDAO;
import ar.uade.distribuidas.tpo.dba.dao.PoliticaDAO;
import ar.uade.distribuidas.tpo.dba.dao.ProveedorDAO;
import ar.uade.distribuidas.tpo.dba.dao.RemitoCPEDAO;
import ar.uade.distribuidas.tpo.dba.dao.RemitoDAO;
import ar.uade.distribuidas.tpo.dba.dao.RodamientoDAO;
import ar.uade.distribuidas.tpo.dba.dao.SolicitudDeCotizacionDAO;
import ar.uade.distribuidas.tpo.dba.dao.StockDAO;
import ar.uade.distribuidas.tpo.dba.dominio.Cliente;
import ar.uade.distribuidas.tpo.dba.dominio.CondicionDeVenta;
import ar.uade.distribuidas.tpo.dba.dominio.Cotizacion;
import ar.uade.distribuidas.tpo.dba.dominio.Factura;
import ar.uade.distribuidas.tpo.dba.dominio.ItemCotizacion;
import ar.uade.distribuidas.tpo.dba.dominio.ItemListaPrecio;
import ar.uade.distribuidas.tpo.dba.dominio.ItemPedido;
import ar.uade.distribuidas.tpo.dba.dominio.ItemRemito;
import ar.uade.distribuidas.tpo.dba.dominio.ItemRemitoCPE;
import ar.uade.distribuidas.tpo.dba.dominio.ItemSolicitudDeCotizacion;
import ar.uade.distribuidas.tpo.dba.dominio.ListaPrecio;
import ar.uade.distribuidas.tpo.dba.dominio.OrdenDeCompra;
import ar.uade.distribuidas.tpo.dba.dominio.OrdenDePedido;
import ar.uade.distribuidas.tpo.dba.dominio.Proveedor;
import ar.uade.distribuidas.tpo.dba.dominio.Remito;
import ar.uade.distribuidas.tpo.dba.dominio.RemitoCPE;
import ar.uade.distribuidas.tpo.dba.dominio.Rodamiento;
import ar.uade.distribuidas.tpo.dba.dominio.SolicitudDeCotizacion;
import ar.uade.distribuidas.tpo.dba.dominio.Stock;

import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;

public class Gestion extends UnicastRemoteObject implements IGestion {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/*
	 * private ClienteDAO cDAO; private StockDAO stockDAO; private
	 * ListaPrecioDAO listaPrecioDAO; private ProveedorDAO proveedorDAO; private
	 * RodamientoDAO rodamientoDAO; private PoliticaDAO politicaDAO; private
	 * SolicitudDeCotizacionDAO scDAO; private CondicionDeVentaDAO
	 * condicionDeVentaDAO; private CotizacionDAO cotizacionDAO;
	 */
	private static Gestion instancia;

	public static Gestion getInstancia() throws RemoteException {
		if (instancia == null) {
			instancia = new Gestion();
		}
		return instancia;
	}

	private Gestion() throws RemoteException {
		super();
		/*
		 * this.cDAO = ClienteDAO.getInstance(); this.cotizacionDAO =
		 * CotizacionDAO.getInstance(); this.listaPrecioDAO =
		 * ListaPrecioDAO.getInstance(); this.politicaDAO =
		 * PoliticaDAO.getInstance(); this.proveedorDAO =
		 * proveedorDAO.getInstance(); this.rodamientoDAO =
		 * rodamientoDAO.getInstance(); this.scDAO =
		 * SolicitudDeCotizacionDAO.getInstance(); this.stockDAO =
		 * stockDAO.getInstance(); this.condicionDeVentaDAO =
		 * CondicionDeVentaDAO.getInstance();
		 */
	}

	// Cliente
	@Override
	public void altaCliente(ClienteDTO cDTO) throws RemoteException {
		Cliente c = Cliente.fromDTO(cDTO);
		ClienteDAO.getInstance().saveOrUpdate(c);
	}

	@Override
	public void bajaCliente(ClienteDTO cDTO) throws RemoteException {
		Cliente c = (Cliente) ClienteDAO.getInstance().get(Cliente.class,
				cDTO.getCuil());
		ClienteDAO.getInstance().delete(c);
	}

	@Override
	public void modificarCliente(ClienteDTO cDTO) throws RemoteException {
		Cliente cli = new Cliente(cDTO);

		ClienteDAO.getInstance().saveOrUpdate(cli);

	}

	/*
	 * public ClienteDAO gethDAO() { return cDAO; }
	 * 
	 * public void setDAO(ClienteDAO hDAO) { this.cDAO = hDAO; }
	 */

	@Override
	public List<ClienteDTO> getClientes() throws RemoteException {

		List<ClienteDTO> dtoList = new LinkedList<ClienteDTO>();
		List<Cliente> clientes = ClienteDAO.getInstance().getAllClientes();
		for (Cliente cli : clientes) {
			dtoList.add(cli.toDTO());
		}
		return dtoList;
	}

	@Override
	public ClienteDTO getCliente(Long cuil) throws RemoteException {
		Cliente cli = (Cliente) ClienteDAO.getInstance().get(Cliente.class,
				cuil);
		if (cli != null)
			return cli.toDTO();
		else
			return null;
	}

	@Override
	public ClienteDTO save(ClienteDTO c) throws RemoteException { // Es igual
																	// que alta
																	// cliente
																	// TODO:
																	// borrar
		// TODO Auto-generated method stub
		return null;
	}

	// Cotizacion
	@Override
	public void saveCotizacion(CotizacionDTO cotDTO) {
		Cotizacion cot = new Cotizacion(cotDTO);
		CotizacionDAO.getInstance().merge(cot);
		

	}

	@Override
	public void updateCotizacion(CotizacionDTO cotDto) {
		Cotizacion cot = new Cotizacion(cotDto);
		CotizacionDAO.getInstance().saveOrUpdate(cot);
	}

	@Override
	public CotizacionDTO getCotizacion(Long id) {
		Cotizacion cotizaDeLaDB = (Cotizacion) CotizacionDAO.getInstance().get(
				Cotizacion.class, id);
		if (cotizaDeLaDB != null)
			return cotizaDeLaDB.toDTO();
		else
			return null;
	}

	// ListaPrecio

	@Override
	public void crearListaPrecio(ListaPrecioDTO lDTO) {

		new ListaPrecio();
		ListaPrecio lp = ListaPrecio.fromDTO(lDTO);

		ListaPrecioDAO.getInstance().saveOrUpdate(lp);

	}

	@Override
	public ListaPrecioDTO getListaPrecio(long id) {
		ListaPrecio lp = (ListaPrecio) ListaPrecioDAO.getInstance().get(ListaPrecio.class, id);
		return lp.toDTO();

	}

	/*
	 * @Override public void crearListaPrecio(ListaPrecioDTO lDTO) {
	 * //this.listaPrecioDAO.saveOrUpdate(ListaPrecioDTO);
	 * 
	 * }
	 */

	@Override
	public void actualizarListaPrecio(ProveedorDTO pDTO) {
		// TODO Auto-generated method stub

	}

	/*
	 * @Override public void crearListaPrecio(ListaPrecioDTO lDTO) {
	 * //this.listaPrecioDAO.saveOrUpdate(ListaPrecioDTO);
	 * 
	 * }
	 */

	@Override
	public ItemListaPrecioDTO getMejorPrecio(RodamientoDTO i, int cant) {
		ItemListaPrecioDTO item = null;
		item = ItemListaPrecioDAO.getInstance().getMejorPrecio(i, cant);
		return item;
	}

	// OrdenDeCompra
	@Override
	public List<OrdenDeCompraDTO> comprarRodamientos() throws RemoteException {

		List<ItemPedido> itemsPedidoPendientes = OrdenDePedidoDAO
				.getInstancia().getItemsPedidoByEstado(
						EstadoItemPedido.PENDIENTE);

		/*
		 * if(itemsPedidoPendientes != null && !itemsPedidoPendientes.isEmpty())
		 * return procesarItemsPedidoCompradosPorCliente(itemsPedidoPendientes);
		 * else
		 */
		return procesarItemsPedidoPendientes(itemsPedidoPendientes);

	}

	private List<OrdenDeCompraDTO> procesarItemsPedidoPendientes(
			List<ItemPedido> itemsPendientes) throws RemoteException {

		List<OrdenDeCompraDTO> ordenesResult = new LinkedList<OrdenDeCompraDTO>();

		Map<Proveedor, List<ItemPedido>> itemsByProveedor = mapItemsByProveedor(itemsPendientes);

		for( Entry<Proveedor, List<ItemPedido>> e : itemsByProveedor.entrySet()) {
			OrdenDeCompraDTO oc = new OrdenDeCompraDTO();
			oc.setEstado(EstadoOC.PENDIENTE);
			oc.setNumero(this.getNroOc());
			oc.setProveedor(e.getKey().toDTO());
			List<ItemListaRodamientoDTO> item = new LinkedList<ItemListaRodamientoDTO>();

			for (ItemPedido i : e.getValue()) {
				ItemListaRodamientoDTO ilr = new ItemListaRodamientoDTO();
				ilr.setCantidad(i.getCantidad());
				Rodamiento rod = (Rodamiento) RodamientoDAO.getInstance().get(Rodamiento.class, i.getRodamientoId());
				RodamientoDTO rdto = rod.toDTO();
				ilr.setRodamiento(rdto);
				item.add(ilr);

				//itemPedido COMPRADO
				this.cambiarEstadoItem(i.getId(), EstadoItemPedido.COMPRADO);
			}
			oc.setItem(item);
			this.altaOC(oc);
			ordenesResult.add(oc);

		}

		// Map<Proveedor, List<ItemPedido>> mapa =
		// mapearItemsPedidoPorProveedores(itemsPendientes);
		// OrdenDeCompra ordenCom = null;
		// List<ItemPedido> itemsPedido = null;
		// Set<Proveedor> proveedores = mapa.keySet();
		// ItemListaRodamiento itemRod = null;
		// List<ItemListaRodamiento> listaItemsOC = null;
		// for (Proveedor proveed : proveedores) {// Saco los itemsPedido de un
		// // determinado
		// // proveedor, armo remito, persisto y lo
		// // agrego al list
		// ordenCom = new OrdenDeCompra(getLastNumberOrdenCompra() + 1,
		// LocalDate.now(), EstadoOC.AROBADA, proveed);
		// itemsPedido = mapa.get(proveed);
		// listaItemsOC = new LinkedList<ItemListaRodamiento>();
		// for (ItemPedido itemPed : itemsPedido) { // proceso los items del
		// // proveedor
		// /*itemRod = new ItemListaRodamiento(itemPed.getItem().getItem()
		// .getRodamiento(), itemPed.getItem().getItem()
		// .getCantidad()); */
		// listaItemsOC.add(itemRod);
		//
		// }
		// ordenCom.setItem(listaItemsOC);
		// OrdenDeCompraDAO.getInstancia().saveOrUpdate(ordenCom);
		// altaOC(ordenCom);
		// ordenesResult.add(ordenCom.toDTO());
		// }

		return ordenesResult;

	}

	private int getNroOc() {
		return (int) (System.currentTimeMillis() % Integer.MAX_VALUE);
	}

	private Map<Proveedor, List<ItemPedido>> mapItemsByProveedor(
			List<ItemPedido> itemsPendientes) {

		Map<Proveedor, List<ItemPedido>> itemsByProveedor = Maps.newHashMap();

		Proveedor p = null;
		List<ItemPedido> listaItems = null;

		for (ItemPedido i : itemsPendientes) {
			Long idItemCot = i.getItemCotizacionId();
			ItemCotizacion itemCot = (ItemCotizacion) CotizacionDAO
					.getInstance().get(ItemCotizacion.class, idItemCot);
			int idItemPrecio = itemCot.getItemListaPrecioId();
			ItemListaPrecio ilp = (ItemListaPrecio) ListaPrecioDAO
					.getInstance().get(ItemListaPrecio.class, idItemPrecio);
			/*long lpId = ilp.getListaPrecioId();
			ListaPrecio lp = (ListaPrecio) ListaPrecioDAO.getInstance().get(
					ListaPrecio.class, lpId);*/
			
			p = ilp.getListaPrecio().getProveedor();

			if (!itemsByProveedor.containsKey(p)) {
				itemsByProveedor.put(p, new LinkedList<ItemPedido>());
			}
			listaItems = itemsByProveedor.get(p);

			listaItems.add(i);
		}

		return itemsByProveedor;
	}

	public int getLastNumberOrdenCompra() {
		return OrdenDeCompraDAO.getInstancia().getLastNumber();
	}

	@SuppressWarnings("unused")
	private Map<Proveedor, List<ItemPedido>> mapearItemsPedidoPorProveedores(
			List<ItemPedido> pedidos) {

		Map<Proveedor, List<ItemPedido>> map = new HashMap<Proveedor, List<ItemPedido>>();
		for (ItemPedido itemPed : pedidos) {

			ItemCotizacionDTO iCot = null;
			try {
				iCot = this.getItemCotizacion(itemPed.getItemCotizacionId());
			} catch (RemoteException e) {
				e.printStackTrace();
			}
			ItemListaPrecioDTO ilpDTO = this.getItemListaPrecio(iCot.getItemListaPrecioId());
			ListaPrecio lp = (ListaPrecio) ListaPrecioDAO.getInstance().get(ListaPrecio.class, ilpDTO.getListaPrecioId());
			ItemListaPrecio ilp = ItemListaPrecio.fromDTO(ilpDTO,lp);
			/*ListaPrecio lp = ListaPrecio.fromDTO(this.getListaPrecio(ilp
					.getListaPrecioId()));*/
			Proveedor key = ilp.getListaPrecio().getProveedor();
			if (map.get(key) == null) {
				map.put(key, new ArrayList<ItemPedido>());
			}
			map.get(key).add(itemPed);
		}

		return map;

	}

	@Override
	public ItemListaPrecioDTO getItemListaPrecio(int itemListaPrecioId) {
		ItemListaPrecio i = (ItemListaPrecio) ListaPrecioDAO.getInstance().get(
				ItemListaPrecio.class, itemListaPrecioId);
		return i.toDTO();
	}

	@Override
	public void recibirMercaderia(Set<RemitoCPEDTO> lop) {
		// List<RemitoCPE> remList = new LinkedList<RemitoCPE>();
		RemitoCPE rem = null;
		for (RemitoCPEDTO remDTO : lop) {
			rem = RemitoCPE.fromDTO(remDTO);
			procesarRemitoCPE(rem);
		}

	}

	private void procesarRemitoCPE(RemitoCPE rem) {

		RemitoCPEDAO.getInstancia().persist(rem);
		for (ItemRemitoCPE item : rem.getItemOC()) {
			Stock stock = StockDAO.getInstance().getStockByRodamientoId(item.getRodamiento().getId());
			if(stock != null){
				stock.setCantidad(item.getCantidad() + stock.getCantidad());	
				StockDAO.getInstance().saveOrUpdate(stock);
			}else{
				stock = new Stock();
				stock.setCantidad(item.getCantidad());
				stock.setRodamiento(item.getRodamiento());
				StockDAO.getInstance().persist(stock);
			}
			

		}

	}

	@Override
	public List<RemitoDTO> procesarItemsPedidoComprados() {

		List<ItemPedido> itemsPedidoComprados = OrdenDePedidoDAO.getInstancia()
				.getItemsPedidoComprado();

		if (itemsPedidoComprados != null && !itemsPedidoComprados.isEmpty())
			return procesarItemsPedidoCompradosPorCliente(itemsPedidoComprados);
		else
			return new LinkedList<RemitoDTO>(); // Si no hay items pendientes,
												// devuelvo una lista vacia
	}

	private Map<Cliente, List<ItemPedido>> mapearItemsPedidoPorClientes(
			List<ItemPedido> pedidos) {

		Map<Cliente, List<ItemPedido>> map = new HashMap<Cliente, List<ItemPedido>>();
		for (ItemPedido itemPed : pedidos) {
			Long opId = itemPed.getOrdenDePedidoId();
			OrdenDePedido op = OrdenDePedidoDAO.getInstancia().getByNumeroOrden(opId);
			
			Cliente key = op.getCliente();
			if (map.get(key) == null) {
				map.put(key, new ArrayList<ItemPedido>());
			}
			map.get(key).add(itemPed);
		}

		return map;

	}

	private List<RemitoDTO> procesarItemsPedidoCompradosPorCliente(
			List<ItemPedido> itemPedidos) {

		Map<Cliente, List<ItemPedido>> mapa = mapearItemsPedidoPorClientes(itemPedidos);
		List<RemitoDTO> remitosDTOResult = new LinkedList<RemitoDTO>();
		List<Stock> stocks;
		HashMap<Stock, Integer> stocksUsados;
		Remito rem = null;
		int iter = 0;
		ItemPedido itemPedido = null;
		Set<Cliente> clientes = mapa.keySet();
		List<ItemPedido> pedidos;

		// Saco los itemsPedido de un determinado
		// Cliente, armo remito, persisto y lo
		// agrego al list
		for (Cliente cli : clientes) {
			

			rem = new Remito(RemitoDAO.getInstancia().getLastNumber() + 1, cli,
					EstadoRemito.NUEVO, LocalDate.now().toString(FormatUtils.DATE_FORMATTER));
			pedidos = mapa.get(cli);
			List<ItemRemito> itemsRem = new LinkedList<ItemRemito>();

			// Proceso itemsPedido del cliente y
			// creo itemsRemito
			while (iter < pedidos.size()) {
				itemPedido = pedidos.get(iter);
				stocksUsados = new HashMap<Stock, Integer>();
				ItemSolicitudDeCotizacion isc = null;
			
					ItemCotizacion iCot = (ItemCotizacion) CotizacionDAO.getInstance().get(ItemCotizacion.class, itemPedido.getItemCotizacionId());
					isc =  (ItemSolicitudDeCotizacion) SolicitudDeCotizacionDAO.getInstance().get(
							ItemSolicitudDeCotizacion.class, iCot.getItemSolicitudId());
				int cant = isc.getCantidad();
				Rodamiento rod = isc.getRodamiento();

				stocks = StockDAO.getInstance().getStockFromRodamiento(rod);
				int i = 0;
				int cantStockUsada;

				// Reviso si con el
				// stock llego a
				// cumplir. Me voy
				// guardando los que uso
				while (cant > 0 && i < stocks.size()) { 
					Stock stockActual = stocks.get(i);
					//cantStock = stockActual.getCantidad();
					if (stockActual.getCantidad() >= cant) {
						cantStockUsada = cant; // seteo la cantidad que
														// use
						cant = 0;

					} else{
						// stockActual.setCantidad(0); voy a usar todo lo que ya
						// tenia. Le va a descontar la misma cantidad que la que
						// tiene
						cantStockUsada = stockActual.getCantidad();
						cant = cant - cantStockUsada;
						
					}
					stocksUsados.put(stockActual, cantStockUsada);

					i++;
				}

				if (cant == 0) { // Si se puede cumplir

					for (Stock stoc : stocksUsados.keySet()) {

						Long opId = itemPedido.getOrdenDePedidoId();
						OrdenDePedido op = (OrdenDePedido) OrdenDePedidoDAO
								.getInstancia().get(OrdenDePedido.class, opId);
						ItemRemito itemRem = new ItemRemito(stocksUsados.get(stoc),
								op.getItemPedidoWithRodamiento(stoc
										.getRodamiento().getId()));

						itemsRem.add(itemRem);

						descontarStock(stoc.getIdStock(), stocksUsados.get(stoc));
					}
					// pedido.setE

					itemPedido.setEstado(EstadoItemPedido.ENVIADO);
					OrdenDePedidoDAO.getInstancia().saveOrUpdate(itemPedido);

				}

				iter++;
			}

			if (!itemsRem.isEmpty()) {// Si tiene itemsRemito, es
										// porque se pudo cumplir
										// con algun itemPedido,
										// sino el remito no se
										// guarda
				rem.setItemsRemito(itemsRem);
				RemitoDAO.getInstancia().persist(rem);
				rem = (Remito) RemitoDAO.getInstancia().get(Remito.class, rem.getNumero());
				remitosDTOResult.add(rem.toDTO());
			}

		}

		return remitosDTOResult; 

	}



	@Override
	public OrdenDeCompraDTO getOrdenCompra(int ordenCompraNumero)
			throws RemoteException {
		OrdenDeCompra orden = (OrdenDeCompra) OrdenDeCompraDAO.getInstancia()
				.getOC(ordenCompraNumero);
		if (orden != null)
			return orden.toDTO();
		else
			return null;
	}

	// Proveedor
	@Override
	public void altaProveedor(ProveedorDTO dto) throws RemoteException {
		Proveedor p = Proveedor.fromDTO(dto);
		ProveedorDAO.getInstance().saveOrUpdate(p);
	}

	@Override
	public void modificarProveedor(ProveedorDTO dto) throws RemoteException {
		Proveedor prov = Proveedor.fromDTO(dto);
		ProveedorDAO.getInstance().saveOrUpdate(prov);
	}

	@Override
	public void bajaProveedor(Long cuil) throws RemoteException {
		Proveedor p = (Proveedor) ProveedorDAO.getInstance().get(
				Proveedor.class, cuil);
		ProveedorDAO.getInstance().delete(p);
	}

	public ProveedorDTO getProveedor(Long cuil) throws RemoteException {
		Proveedor prov = (Proveedor) ProveedorDAO.getInstance().get(
				Proveedor.class, cuil);
		if (prov != null)
			return prov.toDTO();
		else
			return null;
	}

	@Override
	public List<ProveedorDTO> getProveedores() throws RemoteException {
		List<ProveedorDTO> dtoList = new LinkedList<ProveedorDTO>();
		List<Proveedor> proveedores = ProveedorDAO.getInstance()
				.getAllProveedores();
		for (Proveedor prov : proveedores) {
			dtoList.add(prov.toDTO());
		}
		return dtoList;
	}

	@Override
	public ProveedorDTO save(ProveedorDTO c) throws RemoteException { // Lo
																		// mismo
																		// que
																		// alta
																		// proveedor
																		// TODO:
																		// borrar
		// TODO Auto-generated method stub
		return null;
	}

	// Rodamiento

	public static long getSerialversionuid() {
		return serialVersionUID;
	}

	public RodamientoDTO getRodamiento(long serie, String sufijo,
			String marca, String pais) {
		Rodamiento rod = RodamientoDAO.getInstance().getRodamiento(serie,
				sufijo, marca, pais);
		if (rod != null)
			return rod.toDTO();
		else
			return null;
	}

	@Override
	public boolean existeRodamiento(RodamientoDTO rodamientoDTO) {

		return RodamientoDAO.getInstance().getRodamiento(
				rodamientoDTO.getNroSerie(),
				rodamientoDTO.getSufijo(), rodamientoDTO.getMarca(),
				rodamientoDTO.getPais()) != null;
	}

	@Override
	public RodamientoDTO getRodamiento(RodamientoDTO rodamiento)
			throws RemoteException {

		Rodamiento rod; 
		
		if (rodamiento.getIdRodamiento() == null || 
				rodamiento.getIdRodamiento() == 0) {
		rod = RodamientoDAO.getInstance().getRodamiento(
				rodamiento.getNroSerie(),
				rodamiento.getSufijo(), rodamiento.getMarca(),
				rodamiento.getPais());
		} else  {
			rod = (Rodamiento) RodamientoDAO.getInstance().get(Rodamiento.class, rodamiento.getIdRodamiento());
		} 
		return rod.toDTO();
	}

	// Solicitud Cotizacion

	@Override
	public void altaSolicitudDeCotizacion(SolicitudDeCotizacionDTO dto) {
//		Preconditions.checkNotNull(dto.getId());
//		Preconditions.checkNotNull(dto.getCliente());
//		Preconditions.checkNotNull(dto.getFecha());
//		Preconditions.checkNotNull(dto.getItems());

		SolicitudDeCotizacion sc = SolicitudDeCotizacion.fromDTO(dto);
		SolicitudDeCotizacionDAO.getInstance().merge(sc);
	}

	@Override
	public void updateSolicitudDeCotizacion(SolicitudDeCotizacionDTO solDTO) {
		SolicitudDeCotizacion sol = SolicitudDeCotizacion.fromDTO(solDTO);
		SolicitudDeCotizacionDAO.getInstance().saveOrUpdate(sol);
	}

	@Override
	public SolicitudDeCotizacionDTO getById(Long id) {
		SolicitudDeCotizacion sol = (SolicitudDeCotizacion) SolicitudDeCotizacionDAO
				.getInstance().get(SolicitudDeCotizacion.class, id);
		if (sol != null)
			return sol.toDTO();
		else
			return null;
	}

	@Override
	public int getNextItemSCNumber() {
		return SolicitudDeCotizacionDAO.getInstance().getNextItemNumber();
	}

	@Override
	public ItemSolicitudDeCotizacionDTO getItemSolicitudDeCotizacion(Long itemSolicitudId) throws RemoteException {
		ItemSolicitudDeCotizacion i = (ItemSolicitudDeCotizacion) SolicitudDeCotizacionDAO.getInstance().get(
				ItemSolicitudDeCotizacion.class, itemSolicitudId);
		return i.toDTO();
	}

	@Override
	/*
	 * En este caso lo unico que hago es agregar el rodamiento con stock 0. Para
	 * poder agregar stock, hay que actualizarlo
	 */
	public void altaStock(StockDTO stockDTO) {
		Rodamiento r = (Rodamiento) StockDAO
				.getInstance()
				.getSession()
				.get(Rodamiento.class,
						stockDTO.getRodamientoDto().getNroSerie());
		Stock stock = new Stock(stockDTO.getIdStock(), r, 0);
		StockDAO.getInstance().saveOrUpdate(stock);
	}

	@Override
	public void aumentarStock(RodamientoDTO rod, int cantidad) { // Le agrega a la cantidad actual
												// la que trae el DTO
		Stock s = (Stock) StockDAO.getInstance().getStockByRodamientoId(rod.getIdRodamiento());
		if(s!= null){
			s.setCantidad(s.getCantidad() + cantidad);
			StockDAO.getInstance().saveOrUpdate(s);
		}else{
			s = new Stock();
			s.setRodamiento(Rodamiento.fromDTO(rod));
			s.setCantidad(cantidad);
		}
	}

	@Override
	public void bajaStock(StockDTO sDTO) throws RemoteException {
		Stock stoc = new Stock(sDTO);
		StockDAO.getInstance().delete(stoc);
	}

	@Override
	public void elegirMedioPago(PoliticaDTO medioPago) throws RemoteException {

	}

	@Override
	public void altaMedioPago(PoliticaDTO medioPago) throws RemoteException {
		PoliticaDAO.getInstance().saveOrUpdate(medioPago);

	}

	@Override
	public void bajaMedioPago(String id) throws RemoteException {
		PoliticaDTO pol = (PoliticaDTO) PoliticaDAO.getInstance().get(
				PoliticaDTO.class, id);
		if (pol != null)
			PoliticaDAO.getInstance().saveOrUpdate(pol);

	}

	@Override
	public void descontarStock(RodamientoDTO rodamiento, int cant) throws RemoteException {
		Stock s = StockDAO.getInstance().getStockByRodamientoId(rodamiento.getIdRodamiento());
		if(s!=null){
			int cantNueva = s.getCantidad() - cant;
			if (cantNueva > 0)
				s.setCantidad(cantNueva); 
			else
				s.setCantidad(0); // no puede quedar negativo
	
			StockDAO.getInstance().saveOrUpdate(s);
		}
	}

	private void descontarStock(int idStock, int cant) { // Descuenta el stock que se uso
		Stock s = (Stock) StockDAO.getInstance().get(Stock.class,
				idStock);
		if (s.getCantidad() - cant > 0)
			s.setCantidad(s.getCantidad() - cant);
		else
			s.setCantidad(0);

		StockDAO.getInstance().saveOrUpdate(s);

	}

	// CondicionVenta

	@Override
	public void guardarCondicionVenta(CondicionDeVentaDTO condVentDto)
			throws RemoteException {

		Preconditions.checkNotNull(condVentDto.getPorcentaje());
		CondicionDeVenta cond = CondicionDeVenta.fromDTO(condVentDto);
		CondicionDeVentaDAO.getInstance().saveOrUpdate(cond);
	}

	@Override
	public void modificarCondicionVenta(CondicionDeVentaDTO condVentDto)
			throws RemoteException {

		CondicionDeVenta cond = CondicionDeVenta.fromDTO(condVentDto);
		CondicionDeVentaDAO.getInstance().saveOrUpdate(cond);
	}

	@Override
	public CondicionDeVentaDTO getCondicionDeVentaDTO(int id)
			throws RemoteException {

		return ((CondicionDeVenta) CondicionDeVentaDAO.getInstance().get(
				CondicionDeVenta.class, id)).toDTO();
	}

	@Override
	public void altaOrdenDePedido(OrdenDePedidoDTO opDTO)
			throws RemoteException {
		if (opDTO != null) {
			OrdenDePedido odp = OrdenDePedido.fromDTO(opDTO);
			OrdenDePedidoDAO.getInstancia().saveOrUpdate(odp);
		}
	}

	@Override
	public OrdenDePedidoDTO getOrdenDePedido(Long idOdp) throws RemoteException {
		OrdenDePedido odp = (OrdenDePedido) OrdenDePedidoDAO.getInstancia()
				.getByNumeroOrden(idOdp);
		return odp.toDTO();
	}

	@Override
	public void altaRemito(RemitoDTO remitoDTO) throws RemoteException {
		Remito r = Remito.fromDTO(remitoDTO);
		RemitoDAO.getInstancia().persist(r); //.saveOrUpdate(r);
	}

	@Override
	public List<RemitoDTO> getRemitosEmitidos(long cuilCliente) {
		List<Remito> remitos = RemitoDAO.getInstancia().getRemitosEmitidos(
				cuilCliente);
		List<RemitoDTO> dtos = new LinkedList<RemitoDTO>();

		for (Remito r : remitos) {
			dtos.add(r.toDTO());
		}

		return dtos;
	}

	@Override
	public void altaOC(OrdenDeCompraDTO ocDTO) throws RemoteException {
		OrdenDeCompra oc = OrdenDeCompra.fromDTO(ocDTO);
		OrdenDeCompraDAO.getInstancia().saveOrUpdate(oc);

	}

	private void altaOC(OrdenDeCompra oc) throws RemoteException {

		OrdenDeCompraDAO.getInstancia().saveOrUpdate(oc);

	}

	@Override
	public void altaFactura(FacturaDTO dto) {
		FacturaDAO.getInstance().saveOrUpdate(Factura.fromDTO(dto));
	}

	@Override
	public int getProximoNumeroFactura() {
		return FacturaDAO.getInstance().getLastNumber() + 1;
	}

	@Override
	public List<ItemPedidoDTO> getItemsPedidoPendiente() throws RemoteException {
		List<ItemPedido> list = new ArrayList<ItemPedido>();
		list = OrdenDePedidoDAO.getInstancia().getItemsPedidoByEstado(
				EstadoItemPedido.PENDIENTE);
		List<ItemPedidoDTO> lDTO = new ArrayList<ItemPedidoDTO>();

		for (ItemPedido d : list) {
			lDTO.add(d.toDTO());
		}
		return lDTO;
	}

	@Override
	public List<ItemPedidoDTO> getItemsPedidoComprados() throws RemoteException {
		List<ItemPedido> list = new ArrayList<ItemPedido>();
		list = OrdenDePedidoDAO.getInstancia().getItemsPedidoByEstado(
				EstadoItemPedido.COMPRADO);
		List<ItemPedidoDTO> lDTO = new ArrayList<ItemPedidoDTO>();

		for (ItemPedido d : list) {
			lDTO.add(d.toDTO());
		}
		return lDTO;
	}

	@Override
	public void crearListaPrecio(ProveedorDTO pDTO) throws RemoteException {
		// TODO Auto-generated method stub

	}

	@Override
	public void saveRodamiento(RodamientoDTO rodamiento) throws RemoteException {
		RodamientoDAO.getInstance().saveOrUpdate(Rodamiento.fromDTO(rodamiento));
	}

	@Override
	public void altaRodamiento(RodamientoDTO rDTO) throws RemoteException {
		RodamientoDAO.getInstance().saveOrUpdate(Rodamiento.fromDTO(rDTO));
	}

	@Override
	public ItemCotizacionDTO getItemCotizacion(Long itemCotizacionId) throws RemoteException {
		ItemCotizacion ic = (ItemCotizacion) CotizacionDAO.getInstance().get(ItemCotizacion.class, itemCotizacionId);
		return ic.toDTO();
	}

	@Override
	public void cambiarEstadoItem(Long id, EstadoItemPedido estadoNuevo) {
		OrdenDePedidoDAO.getInstancia().cambiarEstadoItem(id, estadoNuevo);
	}

	@Override
	public List<OrdenDePedidoDTO> getOrdenesPedidoByCliente(long cuil) {
		List<OrdenDePedido> ordenes = OrdenDePedidoDAO.getInstancia()
				.getByCliente(cuil);

		List<OrdenDePedidoDTO> ordenesDTO = new LinkedList<OrdenDePedidoDTO>();

		if (ordenes != null && !ordenes.isEmpty()) {

			for (OrdenDePedido orden : ordenes)
				ordenesDTO.add(orden.toDTO());
		}

		return ordenesDTO;
	}

	@Override
	public List<ItemPedidoDTO> getItemsPedidoEnviadosByCliente(long cuil,
			EstadoItemPedido estado) {
		List<ItemPedidoDTO> items = new LinkedList<ItemPedidoDTO>();

		List<OrdenDePedido> ordenes = OrdenDePedidoDAO.getInstancia()
				.getByCliente(cuil);
		if (ordenes != null && !ordenes.isEmpty()) {
			for (OrdenDePedido orden : ordenes) {

				for (ItemPedido item : orden.getItemsPedido()) {

					if (item.getEstado().compareTo(estado) == 0)
						items.add(item.toDTO());

				}

			}
		}
		return items;

	}

	@Override
	public List<ItemPedidoDTO> getItemsPedidoByEstado(EstadoItemPedido estado) {
		List<ItemPedido> items = OrdenDePedidoDAO.getInstancia()
				.getItemsPedidoByEstado(estado);

		List<ItemPedidoDTO> dto = new ArrayList<ItemPedidoDTO>();
		for (ItemPedido item : items) {
			ItemPedidoDTO i = item.toDTO();
			dto.add(i);
		}
		return dto;
	}
	
	@Override
	public CotizacionDTO crearCotizacion(SolicitudDeCotizacionDTO sdto)
			throws RemoteException {
		CotizacionDTO cotizacion = new CotizacionDTO();
		cotizacion.setCliente(sdto.getCliente());
		for (ItemSolicitudDeCotizacionDTO itemSolicitud : sdto.getItems()){
			ItemCotizacionDTO itemCotizacion = new ItemCotizacionDTO();
			itemCotizacion.setCantidad(itemSolicitud.getCantidad());
			itemCotizacion.setItemSolicitudId(itemSolicitud.getId());
			ItemListaPrecioDTO itemLista = this.getMejorPrecio(itemSolicitud.getRodamiento(), itemCotizacion.getCantidad());
			itemCotizacion.setPrecio(Float.valueOf(String.valueOf(itemLista.getCosto())));
			itemCotizacion.setItemListaPrecioId(itemLista.getIdItem());
			itemCotizacion.setSolicitudId(sdto.getId());
			cotizacion.getItemCotizacionDTO().add(itemCotizacion);
		}
		return cotizacion;
	}

	// @Override
	// public Object getClassById(Class clazz, Object id) throws RemoteException
	// {
	// BusinessObject bo = SolicitudDeCotizacionDAO.getInstance().get(clazz,
	// id);
	// return bo.toDTO();
	// }
	@Override
	public void enviarMercaderia(Set<RemitoDTO> remitos) throws RemoteException {

		for (RemitoDTO rem : remitos)
			procesarItemsPedidoEnviados(rem);
	}

	private void procesarItemsPedidoEnviados(RemitoDTO remito) {

		for (ItemRemitoDTO item : remito.getItemsRemito()) {
			item.getItemPedido().setEstado(EstadoItemPedido.ENVIADO);
			cambiarEstadoItem(item.getItemPedido().getId(),
					EstadoItemPedido.ENVIADO);
		}

	}
	
	@Override
	public Map<Long, ItemRemitoDTO> getMapItemPedidoItemRemito(List<ItemPedidoDTO> pedidos) throws RemoteException {
		 Map<Long, ItemRemitoDTO> mapa = new HashMap<Long, ItemRemitoDTO>(); 
		 List<Long> ids = new LinkedList<Long>();
		 
		 for (ItemPedidoDTO pedido : pedidos){
				ids.add(pedido.getId());
		 }
		List<ItemRemito> iRems = RemitoDAO.getInstancia().getItemsRemitoByItemsPedido(ids);
		
		for(ItemRemito itemRem : iRems){
			
			for(Long lon : ids){
				if(lon.compareTo(itemRem.getItemPedido().getId()) ==0 )
					mapa.put(lon, itemRem.toDTO());
				
			}
			
			
		}
		return mapa;
	}

	@Override
	public RemitoDTO getRemitoByNumero(int numero) throws RemoteException {
		Remito rem = (Remito)RemitoDAO.getInstancia().get(Remito.class, numero);
		if(rem!=null)
			return rem.toDTO();
		else
			return null;
	}

	

}
